﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using SocialApi.Core.Extensions;
using SocialApi.Core.Request;
using SocialApi.Instagram.AppSettings;

namespace SocialApi.Instagram.Entities.Methods.Users
{
    internal class UserMethods : IUserMethods
    {
        /// <summary>
        /// Id пользователя
        /// </summary>
        public long Id { get; private set; }

        /// <summary>
        /// Логин
        /// </summary>
        public string UserName { get; private set; }

        /// <summary>
        /// Полное имя
        /// </summary>
        public string FullName { get; private set; }

        /// <summary>
        /// Аватар пользователя
        /// </summary>
        public string ProfilePicture { get; private set; }

        /// <summary>
        /// Биография
        /// </summary>
        public string Biography { get; private set; }

        /// <summary>
        /// Сайт пользователя
        /// </summary>
        public string Site { get; private set; }

        /// <summary>
        /// Тип пользователя
        /// </summary>
        [JsonProperty("type")]
        public string Type { get; private set; }

        /// <summary>
        /// Количество медиа данных пользователя
        /// </summary>
        public ICounts Counts { get; private set; }

        internal static UserMethods This { get; private set; }

        public UserMethods()
        {
            Counts = new CountMethod();
            This = this;
        }

        internal void SetData(IUserMethods user)
        {
            var properties = user.GetType().GetProperties();
            foreach (var propertyInfo in properties)
            {
                switch (propertyInfo.Name)
                {
#if NET_4_5
                    case "Id":
                        Id = propertyInfo.GetValue(user).ConvertTo<long>();
                        break;
                    case "UserName":
                        UserName = propertyInfo.GetValue(user).ToString();
                        break;
                    case "FullName":
                        FullName = propertyInfo.GetValue(user).ToString();
                        break;
                    case "ProfilePicture":
                        ProfilePicture = propertyInfo.GetValue(user).ToString();
                        break;
                    case "Biography":
                        Biography = propertyInfo.GetValue(user).ToString();
                        break;
                    case "Site":
                        Site = propertyInfo.GetValue(user).ToString();
                        break;
                    case "Counts":
                        Counts = CountMethod.This.SetData(propertyInfo.GetValue(user) as ICounts);
                        break;
#else
                    case "Id":
                        Id = propertyInfo.GetValue(user, null).ConvertTo<long>();
                        break;
                    case "UserName":
                        UserName = propertyInfo.GetValue(user, null).ToString();
                        break;
                    case "FullName":
                        FullName = propertyInfo.GetValue(user, null).ToString();
                        break;
                    case "ProfilePicture":
                        ProfilePicture = propertyInfo.GetValue(user, null).ToString();
                        break;
                    case "Biography":
                        Biography = propertyInfo.GetValue(user, null).ToString();
                        break;
                    case "Site":
                        Site = propertyInfo.GetValue(user, null).ToString();
                        break;
                    case "Counts":
                        Counts = CountMethod.This.SetData(propertyInfo.GetValue(user, null) as ICounts);
                        break;
#endif
                }
            }
        }

        #region Члены IUserMethods

        #region Feed

        /// <summary>
        /// Возвращает полную информацию о текущем пользователе
        /// </summary>
        public IEnumerable<IResult> Feed()
        {
            return Feed(0, 0, 0);
        }

        /// <summary>
        /// Возвращает полную информацию о текущем пользователе
        /// </summary>
        /// <param name="minId">Возвращает медиа элементы меньше <see cref="minId"/></param>
        /// <param name="maxId">Возвращает медиа элементы больше <see cref="maxId"/></param>
        public IEnumerable<IResult> Feed(long minId, long maxId)
        {
            return Feed(0, minId, maxId);
        }

        /// <summary>
        /// Возвращает полную информацию о текущем пользователе
        /// </summary>
        /// <param name="count">Количество вовзращаемых медиа элементов</param>
        public IEnumerable<IResult> Feed(int count)
        {
            return Feed(count, 0, 0);
        }

        /// <summary>
        /// Возвращает полную информацию о текущем пользователе
        /// </summary>
        /// <param name="count">Количество вовзращаемых медиа элементов</param>
        /// <param name="minId">Возвращает медиа элементы меньше <see cref="minId"/></param>
        /// <param name="maxId">Возвращает медиа элементы больше <see cref="maxId"/></param>
        public IEnumerable<IResult> Feed(int count, long minId, long maxId)
        {
            var url = CreateFeedUrl(count, minId, maxId);
            var jObject = JObject.Parse(Navigator.Instance.Get(url));
            InstagramService.CheckResult(jObject);
#if NET_4_5 || NET_4_0
            return jObject["data"].ToObject<IEnumerable<Result>>();
#else
            return jObject["data"].ToObject<List<Result>>() as IEnumerable<IResult>;
#endif
        }

        /// <summary>
        /// Возвращает полную информацию о текущем пользователе
        /// </summary>
        public async Task<IEnumerable<IResult>> FeedAsync()
        {
            var result = await FeedAsync(0, 0, 0);
            return result;
        }

        /// <summary>
        /// Возвращает полную информацию о текущем пользователе
        /// </summary>
        /// <param name="minId">Возвращает медиа элементы меньше <see cref="minId"/></param>
        /// <param name="maxId">Возвращает медиа элементы больше <see cref="maxId"/></param>
        public async Task<IEnumerable<IResult>> FeedAsync(long minId, long maxId)
        {
            var result = await FeedAsync(0, minId, maxId);
            return result;
        }

        /// <summary>
        /// Возвращает полную информацию о текущем пользователе
        /// </summary>
        /// <param name="count">Количество вовзращаемых медиа элементов</param>
        public async Task<IEnumerable<IResult>> FeedAsync(int count)
        {
            var result = await FeedAsync(count, 0, 0);
            return result;
        }

        /// <summary>
        /// Возвращает полную информацию о текущем пользователе
        /// </summary>
        /// <param name="count">Количество вовзращаемых медиа элементов</param>
        /// <param name="minId">Возвращает медиа элементы меньше <see cref="minId"/></param>
        /// <param name="maxId">Возвращает медиа элементы больше <see cref="maxId"/></param>
        public async Task<IEnumerable<IResult>> FeedAsync(int count, long minId, long maxId)
        {
            var url = CreateFeedUrl(count, minId, maxId);
            var result = await Navigator.Instance.GetAsync(url);
            var jObject = JObject.Parse(result);
            InstagramService.CheckResult(jObject);
#if NET_4_5 || NET_4_0
            return jObject["data"].ToObject<IEnumerable<Result>>();
#else
            return jObject["data"].ToObject<List<Result>>() as IEnumerable<IResult>;
#endif
        }

        private static string CreateFeedUrl(int count, long minId, long maxId)
        {
            var url = new StringBuilder(InstagramService.GetMethodUrl(ApiUrls.ApiBaseUrl, ApiUrls.UserApi, ApiUrls.UserFeed));
            if (count != 0)
            {
                url.AppendFormat("&count={0}", count);
            }
            if (minId != 0)
            {
                url.AppendFormat("&min_id={0}", minId);
            }
            if (maxId != 0)
            {
                url.AppendFormat("&max_id={0}", maxId);
            }
            return url.ToString();
        }

        #endregion

        #region Info

        /// <summary>
        /// Возвращает базовую информацию о текущем пользователе
        /// </summary>
        public IUserMethods Info()
        {
            return Info(Id);
        }

        /// <summary>
        /// Возвращает базовую информацию о пользователе
        /// </summary>
        /// <param name="userId">Id пользователя, данные которого хотим узнать</param>
        public IUserMethods Info(long userId)
        {
            var url = InstagramService.GetMethodUrl(ApiUrls.ApiBaseUrl, ApiUrls.UserApi, string.Format("{0}/", userId));
            var jObject = JObject.Parse(Navigator.Instance.Get(url));
            InstagramService.CheckResult(jObject);
            var result = jObject["data"].ToObject<UserMethods>();
            if (userId == Id)
            {
                SetData(result);
            }
            return result;
        }

        /// <summary>
        /// Асинхроно возвращает базовую информацию о текущем пользователе
        /// </summary>
        public async Task<IUserMethods> InfoAsync()
        {
            var result = await InfoAsync(Id);
            return result;
        }

        /// <summary>
        /// Асинхроно возвращает базовую информацию о пользователе
        /// </summary>
        /// <param name="userId">Id пользователя, данные которого хотим узнать</param>
        public async Task<IUserMethods> InfoAsync(long userId)
        {
            var url = InstagramService.GetMethodUrl(ApiUrls.ApiBaseUrl, ApiUrls.UserApi, string.Format("{0}/", userId));
            var result = await Navigator.Instance.GetAsync(url);
            var jObject = JObject.Parse(result);
            InstagramService.CheckResult(jObject);
            var user = jObject["data"].ToObject<UserMethods>();
            if (userId == Id)
            {
                SetData(user);
            }
            return user;
        }

        #endregion

        #region Search

        /// <summary>
        /// Выполняет синхронный поиск пользователей
        /// </summary>
        /// <param name="query">Имя пользователя</param>
        public IEnumerable<IUserMethods> Search(string query)
        {
            return Search(query, 0);
        }

        /// <summary>
        /// Выполняет синхронный поиск пользователей
        /// </summary>
        /// <param name="query">Имя пользователя</param>
        /// <param name="count">Количество возвращемых пользователей</param>
        public IEnumerable<IUserMethods> Search(string query, int count)
        {
            var jObject = JObject.Parse(Navigator.Instance.Get(CreateSearchUrl(query, count)));
            InstagramService.CheckResult(jObject);
#if NET_4_5 || NET_4_0
            return jObject["data"].ToObject<IEnumerable<UserMethods>>();
#else
            return jObject["data"].ToObject<List<UserMethods>>() as IEnumerable<IUserMethods>;
#endif
        }

        /// <summary>
        /// Выполняет синхронный поиск пользователей
        /// </summary>
        /// <param name="query">Имя пользователя</param>
        public async Task<IEnumerable<IUserMethods>> SearchAsync(string query)
        {
            var result = await SearchAsync(query, 0);
            return result;
        }

        /// <summary>
        /// Выполняет синхронный поиск пользователей
        /// </summary>
        /// <param name="query">Имя пользователя</param>
        /// <param name="count">Количество возвращемых пользователей</param>
        public async Task<IEnumerable<IUserMethods>> SearchAsync(string query, int count)
        {
            var request = await Navigator.Instance.GetAsync(CreateSearchUrl(query, count));
            var jObject = JObject.Parse(request);
            InstagramService.CheckResult(jObject);
#if NET_4_5 || NET_4_0
            return jObject["data"].ToObject<IEnumerable<UserMethods>>();
#else
            return jObject["data"].ToObject<List<UserMethods>>() as IEnumerable<IUserMethods>;
#endif
        }

        private static string CreateSearchUrl(string query, int count)
        {
            var url = new StringBuilder(InstagramService.GetMethodUrl(ApiUrls.ApiBaseUrl, ApiUrls.UserApi, ApiUrls.Search));
            url.AppendFormat("&q={0}", query);
            if (count != 0)
            {
                url.AppendFormat("&count={0}", count);
            }
            return url.ToString();
        }

        #endregion

        #region Liked

        /// <summary>
        /// Возвращает полную информация о понравишемся объекте
        /// </summary>
        /// <returns>Полная информация о понравишемся объекте</returns>
        public IEnumerable<IResult> Liked()
        {
            return Liked(100, -1);
        }

        /// <summary>
        /// Возвращает полную информация о понравишемся объекте
        /// </summary>
        /// <param name="count">Количество, возвращаемых записей</param>
        /// <returns>Полная информация о понравишемся объекте</returns>
        public IEnumerable<IResult> Liked(int count)
        {
            return Liked(count, -1);
        }

        /// <summary>
        /// Возвращает полную информация о понравишемся объекте
        /// </summary>
        /// <param name="maxLikeId">Возвращает записи меньше текущего Id</param>
        /// <returns>Полная информация о понравишемся объекте</returns>
        public IEnumerable<IResult> Liked(long maxLikeId)
        {
            return Liked(100, maxLikeId);
        }

        /// <summary>
        /// Возвращает полную информация о понравишемся объекте
        /// </summary>
        /// <param name="count">Количество, возвращаемых записей</param>
        /// <param name="maxLikeId">Возвращает записи меньше текущего Id</param>
        /// <returns>Полная информация о понравишемся объекте</returns>
        public IEnumerable<IResult> Liked(int count, long maxLikeId)
        {
            var url = CreateLikedUrl(count, maxLikeId);
            var jObject = JObject.Parse(Navigator.Instance.Get(url));
            InstagramService.CheckResult(jObject);
#if NET_4_5 || NET_4_0
            return jObject["data"].ToObject<IEnumerable<Result>>();
#else
            return jObject["data"].ToObject<List<Result>>() as IEnumerable<IResult>;
#endif
        }

        /// <summary>
        /// Асинхронно возвращает полную информация о понравишемся объекте
        /// </summary>
        /// <returns>Полная информация о понравишемся объекте</returns>
        public async Task<IEnumerable<IResult>> LikedAsync()
        {
            var result = await LikedAsync(100, -1);
            return result;
        }

        /// <summary>
        /// Асинхронно возвращает полную информация о понравишемся объекте
        /// </summary>
        /// <param name="count">Количество, возвращаемых записей</param>
        /// <returns>Полная информация о понравишемся объекте</returns>
        public async Task<IEnumerable<IResult>> LikedAsync(int count)
        {
            var result = await LikedAsync(count, -1);
            return result;
        }

        /// <summary>
        /// Асинхронно возвращает полную информация о понравишемся объекте
        /// </summary>
        /// <param name="maxLikeId">Возвращает записи меньше текущего Id</param>
        /// <returns>Полная информация о понравишемся объекте</returns>
        public async Task<IEnumerable<IResult>> LikedAsync(long maxLikeId)
        {
            var result = await LikedAsync(100, maxLikeId);
            return result;
        }

        /// <summary>
        /// Асинхронно возвращает полную информация о понравишемся объекте
        /// </summary>
        /// <param name="count">Количество, возвращаемых записей</param>
        /// <param name="maxLikeId">Возвращает записи меньше текущего Id</param>
        /// <returns>Полная информация о понравишемся объекте</returns>
        public async Task<IEnumerable<IResult>> LikedAsync(int count, long maxLikeId)
        {
            var url = CreateLikedUrl(count, maxLikeId);
            var result = await Navigator.Instance.GetAsync(url);
            var jObject = JObject.Parse(result);
            InstagramService.CheckResult(jObject);
#if NET_4_5 || NET_4_0
            return jObject["data"].ToObject<IEnumerable<Result>>();
#else
            return jObject["data"].ToObject<List<Result>>() as IEnumerable<IResult>;
#endif
        }

        private static string CreateLikedUrl(int count, long maxLikeId)
        {
            var result = new StringBuilder(InstagramService.GetMethodUrl(ApiUrls.ApiBaseUrl, ApiUrls.UserApi, "self/", ApiUrls.Media, "liked"));
            result.AppendFormat("&count={0}", count);
            if (maxLikeId.Exists())
            {
                result.AppendFormat("&max_like_id={0}", maxLikeId);
            }
            return result.ToString();
        }

        #endregion

        #region Recent

        /// <summary>
        /// Возращает последние файлы пользователя
        /// </summary>
        /// <returns>Последние файлы пользователя</returns>
        public IEnumerable<IResult> Recent()
        {
            return Recent(Id, 100, -1, -1, null, null);
        }

        /// <summary>
        /// Возвращает последние файлы пользователя
        /// </summary>
        /// <param name="userId">Id пользователя</param>
        /// <returns>Последние файлы пользователя</returns>
        public IEnumerable<IResult> Recent(long userId)
        {
            return Recent(userId, 100, -1, -1, null, null);
        }

        /// <summary>
        /// Возвращает последние файлы пользователя
        /// </summary>
        /// <param name="count">Количество, возвращаемых данных</param>
        /// <returns>Последние файлы пользователя</returns>
        public IEnumerable<IResult> Recent(int count)
        {
            return Recent(Id, count, -1, -1, null, null);
        }

        /// <summary>
        /// Возвращает последние файлы пользователя
        /// </summary>
        /// <param name="userId">Id пользователя</param>
        /// <param name="count">Количество, возвращаемых данных</param>
        /// <returns>Последние файлы пользователя</returns>
        public IEnumerable<IResult> Recent(long userId, int count)
        {
            return Recent(userId, count, -1, -1, null, null);
        }

        /// <summary>
        /// Возвращает последние файлы пользователя
        /// </summary>
        /// <param name="minId">Возвращает данные меньше заданного Id</param>
        /// <param name="maxId">Возвращает данные больше заданного Id</param>
        /// <returns>Последние файлы пользователя</returns>
        public IEnumerable<IResult> Recent(long minId, long maxId)
        {
            return Recent(Id, 100, minId, maxId, null, null);
        }

        /// <summary>
        /// Возвращает последние файлы пользователя
        /// </summary>
        /// <param name="userId">Id пользователя</param>
        /// <param name="minId">Возвращает данные меньше заданного Id</param>
        /// <param name="maxId">Возвращает данные больше заданного Id</param>
        /// <returns>Последние файлы пользователя</returns>
        public IEnumerable<IResult> Recent(long userId, long minId, long maxId)
        {
            return Recent(userId, 100, minId, maxId, null, null);
        }

        /// <summary>
        /// Возвращает последние файлы пользователя
        /// </summary>
        /// <param name="count">Количество, возвращаемых данных</param>
        /// <param name="minId">Возвращает данные меньше заданного Id</param>
        /// <param name="maxId">Возвращает данные больше заданного Id</param>
        /// <returns>Последние файлы пользователя</returns>
        public IEnumerable<IResult> Recent(int count, long minId, long maxId)
        {
            return Recent(Id, count, minId, maxId, null, null);
        }

        /// <summary>
        /// Возвращает последние файлы пользователя
        /// </summary>
        /// <param name="userId">Id пользователя</param>
        /// <param name="count">Количество, возвращаемых данных</param>
        /// <param name="minId">Возвращает данные меньше заданного Id</param>
        /// <param name="maxId">Возвращает данные больше заданного Id</param>
        /// <returns>Последние файлы пользователя</returns>
        public IEnumerable<IResult> Recent(long userId, int count, long minId, long maxId)
        {
            return Recent(userId, count, minId, maxId, null, null);
        }

        /// <summary>
        /// Возвращает последние файлы пользователя
        /// </summary>
        /// <param name="min">Возвращает данные, после текущего времени</param>
        /// <param name="max">Возвращает данные, до текущего времени</param>
        /// <returns>Последние файлы пользователя</returns>
        public IEnumerable<IResult> Recent(DateTime? min, DateTime? max)
        {
            return Recent(Id, 100, -1, -1, min, max);
        }

        /// <summary>
        /// Возвращает последние файлы пользователя
        /// </summary>
        /// <param name="userId">Id пользователя</param>
        /// <param name="min">Возвращает данные, после текущего времени</param>
        /// <param name="max">Возвращает данные, до текущего времени</param>
        /// <returns>Последние файлы пользователя</returns>
        public IEnumerable<IResult> Recent(long userId, DateTime? min, DateTime? max)
        {
            return Recent(userId, 100, -1, -1, min, max);
        }

        /// <summary>
        /// Возвращает последние файлы пользователя
        /// </summary>
        /// <param name="count">Количество, возвращаемых данных</param>
        /// <param name="min">Возвращает данные, после текущего времени</param>
        /// <param name="max">Возвращает данные, до текущего времени</param>
        /// <returns>Последние файлы пользователя</returns>
        public IEnumerable<IResult> Recent(int count, DateTime? min, DateTime? max)
        {
            return Recent(Id, count, -1, -1, min, max);
        }

        /// <summary>
        /// Возвращает последние файлы пользователя
        /// </summary>
        /// <param name="userId">Id пользователя</param>
        /// <param name="count">Количество, возвращаемых данных</param>
        /// <param name="min">Возвращает данные, после текущего времени</param>
        /// <param name="max">Возвращает данные, до текущего времени</param>
        /// <returns>Последние файлы пользователя</returns>
        public IEnumerable<IResult> Recent(long userId, int count, DateTime? min, DateTime? max)
        {
            return Recent(userId, count, -1, -1, min, max);
        }

        /// <summary>
        /// Возвращает последние файлы пользователя
        /// </summary>
        /// <param name="minId">Возвращает данные меньше заданного Id</param>
        /// <param name="maxId">Возвращает данные больше заданного Id</param>
        /// <param name="min">Возвращает данные, после текущего времени</param>
        /// <param name="max">Возвращает данные, до текущего времени</param>
        /// <returns>Последние файлы пользователя</returns>
        public IEnumerable<IResult> Recent(long minId, long maxId, DateTime? min, DateTime? max)
        {
            return Recent(Id, 100, minId, maxId, min, max);
        }

        /// <summary>
        /// Возвращает последние файлы пользователя
        /// </summary>
        /// <param name="userId">Id пользователя</param>
        /// <param name="minId">Возвращает данные меньше заданного Id</param>
        /// <param name="maxId">Возвращает данные больше заданного Id</param>
        /// <param name="min">Возвращает данные, после текущего времени</param>
        /// <param name="max">Возвращает данные, до текущего времени</param>
        /// <returns>Последние файлы пользователя</returns>
        public IEnumerable<IResult> Recent(long userId, long minId, long maxId, DateTime? min, DateTime? max)
        {
            return Recent(userId, 100, minId, maxId, min, max);
        }

        /// <summary>
        /// Возвращает последние файлы пользователя
        /// </summary>
        /// <param name="count">Количество, возвращаемых данных</param>
        /// <param name="minId">Возвращает данные меньше заданного Id</param>
        /// <param name="maxId">Возвращает данные больше заданного Id</param>
        /// <param name="min">Возвращает данные, после текущего времени</param>
        /// <param name="max">Возвращает данные, до текущего времени</param>
        /// <returns>Последние файлы пользователя</returns>
        public IEnumerable<IResult> Recent(int count, long minId, long maxId, DateTime? min, DateTime? max)
        {
            return Recent(Id, count, minId, maxId, min, max);
        }

        /// <summary>
        /// Возвращает последние файлы пользователя
        /// </summary>
        /// <param name="userId">Id пользователя</param>
        /// <param name="count">Количество, возвращаемых данных</param>
        /// <param name="minId">Возвращает данные меньше заданного Id</param>
        /// <param name="maxId">Возвращает данные больше заданного Id</param>
        /// <param name="min">Возвращает данные, после текущего времени</param>
        /// <param name="max">Возвращает данные, до текущего времени</param>
        /// <returns>Последние файлы пользователя</returns>
        public IEnumerable<IResult> Recent(long userId, int count, long minId, long maxId, DateTime? min, DateTime? max)
        {
            var url = CreateRecentUrl(userId, count, minId, maxId, min, max);
            var jObject = JObject.Parse(Navigator.Instance.Get(url));
            InstagramService.CheckResult(jObject);
#if NET_4_5 || NET_4_0
            return jObject["data"].ToObject<IEnumerable<Result>>();
#else
            return jObject["data"].ToObject<List<Result>>() as IEnumerable<IResult>;
#endif
        }

        /// <summary>
        /// Асинхронно возвращает последние файлы пользователя
        /// </summary>
        /// <returns>Последние файлы пользователя</returns>
        public async Task<IEnumerable<IResult>> RecentAsync()
        {
            var result = await RecentAsync(Id, 100, -1, -1, null, null);
            return result;
        }

        /// <summary>
        /// Асинхронно возвращает последние файлы пользователя
        /// </summary>
        /// <param name="userId">Id пользователя</param>
        /// <returns>Последние файлы пользователя</returns>
        public async Task<IEnumerable<IResult>> RecentAsync(long userId)
        {
            var result = await RecentAsync(userId, 100, -1, -1, null, null);
            return result;
        }

        /// <summary>
        /// Асинхронно возвращает последние файлы пользователя
        /// </summary>
        /// <param name="count">Количество, возвращаемых данных</param>
        /// <returns>Последние файлы пользователя</returns>
        public async Task<IEnumerable<IResult>> RecentAsync(int count)
        {
            var result = await RecentAsync(Id, count, -1, -1, null, null);
            return result;
        }

        /// <summary>
        /// Асинхронно возвращает последние файлы пользователя
        /// </summary>
        /// <param name="userId">Id пользователя</param>
        /// <param name="count">Количество, возвращаемых данных</param>
        /// <returns>Последние файлы пользователя</returns>
        public async Task<IEnumerable<IResult>> RecentAsync(long userId, int count)
        {
            var result = await RecentAsync(userId, count, -1, -1, null, null);
            return result;
        }

        /// <summary>
        /// Асинхронно возвращает последние файлы пользователя
        /// </summary>
        /// <param name="minId">Возвращает данные меньше заданного Id</param>
        /// <param name="maxId">Возвращает данные больше заданного Id</param>
        /// <returns>Последние файлы пользователя</returns>
        public async Task<IEnumerable<IResult>> RecentAsync(long minId, long maxId)
        {
            var result = await RecentAsync(Id, 100, minId, maxId, null, null);
            return result;
        }

        /// <summary>
        /// Асинхронно возвращает последние файлы пользователя
        /// </summary>
        /// <param name="userId">Id пользователя</param>
        /// <param name="minId">Возвращает данные меньше заданного Id</param>
        /// <param name="maxId">Возвращает данные больше заданного Id</param>
        /// <returns>Последние файлы пользователя</returns>
        public async Task<IEnumerable<IResult>> RecentAsync(long userId, long minId, long maxId)
        {
            var result = await RecentAsync(userId, 100, minId, maxId, null, null);
            return result;
        }

        /// <summary>
        /// Асинхронно возвращает последние файлы пользователя
        /// </summary>
        /// <param name="count">Количество, возвращаемых данных</param>
        /// <param name="minId">Возвращает данные меньше заданного Id</param>
        /// <param name="maxId">Возвращает данные больше заданного Id</param>
        /// <returns>Последние файлы пользователя</returns>
        public async Task<IEnumerable<IResult>> RecentAsync(int count, long minId, long maxId)
        {
            var result = await RecentAsync(Id, count, minId, maxId, null, null);
            return result;
        }

        /// <summary>
        /// Асинхронно возвращает последние файлы пользователя
        /// </summary>
        /// <param name="userId">Id пользователя</param>
        /// <param name="count">Количество, возвращаемых данных</param>
        /// <param name="minId">Возвращает данные меньше заданного Id</param>
        /// <param name="maxId">Возвращает данные больше заданного Id</param>
        /// <returns>Последние файлы пользователя</returns>
        public async Task<IEnumerable<IResult>> RecentAsync(long userId, int count, long minId, long maxId)
        {
            var result = await RecentAsync(userId, count, minId, maxId, null, null);
            return result;
        }

        /// <summary>
        /// Асинхронно возвращает последние файлы пользователя
        /// </summary>
        /// <param name="min">Возвращает данные, после текущего времени</param>
        /// <param name="max">Возвращает данные, до текущего времени</param>
        /// <returns>Последние файлы пользователя</returns>
        public async Task<IEnumerable<IResult>> RecentAsync(DateTime? min, DateTime? max)
        {
            var result = await RecentAsync(Id, 100, -1, -1, min, max);
            return result;
        }

        /// <summary>
        /// Асинхронно возвращает последние файлы пользователя
        /// </summary>
        /// <param name="userId">Id пользователя</param>
        /// <param name="min">Возвращает данные, после текущего времени</param>
        /// <param name="max">Возвращает данные, до текущего времени</param>
        /// <returns>Последние файлы пользователя</returns>
        public async Task<IEnumerable<IResult>> RecentAsync(long userId, DateTime? min, DateTime? max)
        {
            var result = await RecentAsync(userId, 100, -1, -1, min, max);
            return result;
        }

        /// <summary>
        /// Асинхронно возвращает последние файлы пользователя
        /// </summary>
        /// <param name="count">Количество, возвращаемых данных</param>
        /// <param name="min">Возвращает данные, после текущего времени</param>
        /// <param name="max">Возвращает данные, до текущего времени</param>
        /// <returns>Последние файлы пользователя</returns>
        public async Task<IEnumerable<IResult>> RecentAsync(int count, DateTime? min, DateTime? max)
        {
            var result = await RecentAsync(Id, count, -1, -1, min, max);
            return result;
        }

        /// <summary>
        /// Асинхронно возвращает последние файлы пользователя
        /// </summary>
        /// <param name="userId">Id пользователя</param>
        /// <param name="count">Количество, возвращаемых данных</param>
        /// <param name="min">Возвращает данные, после текущего времени</param>
        /// <param name="max">Возвращает данные, до текущего времени</param>
        /// <returns>Последние файлы пользователя</returns>
        public async Task<IEnumerable<IResult>> RecentAsync(long userId, int count, DateTime? min, DateTime? max)
        {
            var result = await RecentAsync(userId, count, -1, -1, min, max);
            return result;
        }

        /// <summary>
        /// Асинхронно возвращает последние файлы пользователя
        /// </summary>
        /// <param name="minId">Возвращает данные меньше заданного Id</param>
        /// <param name="maxId">Возвращает данные больше заданного Id</param>
        /// <param name="min">Возвращает данные, после текущего времени</param>
        /// <param name="max">Возвращает данные, до текущего времени</param>
        /// <returns>Последние файлы пользователя</returns>
        public async Task<IEnumerable<IResult>> RecentAsync(long minId, long maxId, DateTime? min, DateTime? max)
        {
            var result = await RecentAsync(Id, 100, minId, maxId, min, max);
            return result;
        }

        /// <summary>
        /// Асинхронно возвращает последние файлы пользователя
        /// </summary>
        /// <param name="userId">Id пользователя</param>
        /// <param name="minId">Возвращает данные меньше заданного Id</param>
        /// <param name="maxId">Возвращает данные больше заданного Id</param>
        /// <param name="min">Возвращает данные, после текущего времени</param>
        /// <param name="max">Возвращает данные, до текущего времени</param>
        /// <returns>Последние файлы пользователя</returns>
        public async Task<IEnumerable<IResult>> RecentAsync(long userId, long minId, long maxId, DateTime? min, DateTime? max)
        {
            var result = await RecentAsync(userId, 100, minId, maxId, min, max);
            return result;
        }

        /// <summary>
        /// Асинхронно возвращает последние файлы пользователя
        /// </summary>
        /// <param name="count">Количество, возвращаемых данных</param>
        /// <param name="minId">Возвращает данные меньше заданного Id</param>
        /// <param name="maxId">Возвращает данные больше заданного Id</param>
        /// <param name="min">Возвращает данные, после текущего времени</param>
        /// <param name="max">Возвращает данные, до текущего времени</param>
        /// <returns>Последние файлы пользователя</returns>
        public async Task<IEnumerable<IResult>> RecentAsync(int count, long minId, long maxId, DateTime? min, DateTime? max)
        {
            var result = await RecentAsync(Id, count, minId, maxId, min, max);
            return result;
        }

        /// <summary>
        /// Асинхронно возвращает последние файлы пользователя
        /// </summary>
        /// <param name="userId">Id пользователя</param>
        /// <param name="count">Количество, возвращаемых данных</param>
        /// <param name="minId">Возвращает данные меньше заданного Id</param>
        /// <param name="maxId">Возвращает данные больше заданного Id</param>
        /// <param name="min">Возвращает данные, после текущего времени</param>
        /// <param name="max">Возвращает данные, до текущего времени</param>
        /// <returns>Последние файлы пользователя</returns>
        public async Task<IEnumerable<IResult>> RecentAsync(long userId, int count, long minId, long maxId, DateTime? min, DateTime? max)
        {
            var url = CreateRecentUrl(userId, count, minId, maxId, min, max);
            var result = await Navigator.Instance.GetAsync(url);
            var jObject = JObject.Parse(result);
            InstagramService.CheckResult(jObject);
#if NET_4_5 || NET_4_0
            return jObject["data"].ToObject<IEnumerable<Result>>();
#else
            return jObject["data"].ToObject<List<Result>>() as IEnumerable<IResult>;
#endif
        }

        private static string CreateRecentUrl(long userId, int count, long minId, long maxId, DateTime? min, DateTime? max)
        {
            var result = new StringBuilder(InstagramService.GetMethodUrl(ApiUrls.ApiBaseUrl, ApiUrls.UserApi, userId.ToInvariantString(), "/", ApiUrls.Media, "recent/"));
            result.AppendFormat("&count={0}", count);
            if (minId.Exists())
            {
                result.AppendFormat("&min_id={0}", minId);
            }
            if (maxId.Exists())
            {
                result.AppendFormat("&max_id={0}", maxId);
            }
            if (min.Exists())
            {
                if (min.HasValue)
                {
                    result.AppendFormat("&min_timestamp={0}", min.Value.ToUnixTimestamp());
                }
            }
            if (max.Exists())
            {
                if (max.HasValue)
                {
                    result.AppendFormat("&max_timestamp={0}", max.Value.ToUnixTimestamp());
                }
            }
            return result.ToString();
        }

        #endregion

        #endregion
    }
}